/**
*  SoundManager.h
*
*  Original Code : Van Stokes, Jr. (http://www.EvilMasterMindsInc.com) - Aug 05
*  Modified Code : Steven Gay - mec3@bluewin.ch - Septembre 2005 - Jan 06
*
*
*                    Partial Documentation
*                    =====================
*
*  Very simple SoundManager using OpenAl. 
*
*  For a more complete one, you should see :
*  OpenAL++ http://alpp.sourceforge.net/
*
****************************************************************************
*  COMPILE
*
*  - Don't forget to link to : ALut.lib and OpenAL32.lib.
*    The order is important.
*
*  - With CodeBlocks there is one warning I didn't resolve :
*     "Warning: .drectve `/DEFAULTLIB:"uuid.lib" /DEFAULTLIB:"uuid.lib" ' unrecognized"
*
****************************************************************************
*  USAGE
*
* 1. Create the object from the class with createManager()
*
* 2. Call the init() function
*
* 3. Call the loadDefaultSounds() function to PRE-LOAD audio into the buffers.
*    This is optional. Review the function to make changes that you need.
*
* 4. Set the Listener Location by calling setListenerPosition() function
*    continually call this as your Listener (camera) position changes!
*
* 5. For each object that emits sound, call the loadSound() function.
*    CAREFUL : The filename must be unique.
*
* 6. Optional : For each object you can set the all the parameters of the
*    sound with setSound() or only the position, velocity and direction with
*    setSoundPosition().
*
* 7. Call the playAudioSource() to play the sound at some event.
*    This function will play the sound and then stop. It will NOT repeat playing.
*    Use stopAudioSource() to stop a sound from playing if its still playing
*
* 8. Call pauseAudio() or pauseAllAudio() to pause one or all sound(s).
*    Call resumeAudio() or resumeAllAudio() to resume one or all paused sound(s).
*
* 9. When your object is done emitting sounds (when out of range for example)
*    call releaseAudioSource().
*    It is important to release your source when you are no longer going to
*    need it because you are limited in the number of sources you can have.
*
* 10. If your objects moves (other than the listener/camera) then
*    continually update the objects position by calling setSourcePosition().
*
******************************************************************************
* 
* Additional informations :
*
* Ogg Vorbis - http://www.xiph.org/downloads/
*            - http://www.illiminable.com/ogg/
* Flac       - http://flac.sourceforge.net/features.html
* Theora     - http://www.theora.org/
*
*
******************************************************************************
*
* TODO
*
* loadOGG()
* alSourcePause()
*
* Use the EAX functions !
*
******************************************************************************/

#ifndef __SOUNDMANAGER_H__
#define __SOUNDMANAGER_H__

#include <stdio.h>
#include <string>

// Comment this line if you don't have the EAX 2.0 SDK installed
//#define _USEEAX

#ifdef _USEEAX
    #include "eax.h"
#endif

// OpenAl version 1.0
// #include <al/alctypes.h>
// #include <al/altypes.h>
// #include <al/alc.h>
// #include <al/al.h>
// #include <alut/alut.h>
// OpenAl version 1.1
#include <al.h>
#include <alc.h>
#include <alut.h>
#define OGRE
// Modify this as you need.
#ifdef OGRE
   #include "OgreVector3.h"
   #include "OgreQuaternion.h"
   using namespace Ogre;
#else
   #include "Vector3.h"
   using namespace gameengine::utilities;
#endif

// Be very careful with these two parameters
// It is very dependant on the audio hardware your
// user is using. It you get too large, it may work
// on one persons system but not on another.
// TODO Write a fct testing the hardware !
#define MAX_AUDIO_BUFFERS   64
#define MAX_AUDIO_SOURCES   16

// Used to store sound filenames
#define MAX_FILENAME_LENGTH 40

class SoundManager
{
  private:
       // EAX related
       bool isEAXPresent;
#ifdef _USEEAX
       // EAX 2.0 GUIDs
       const GUID DSPROPSETID_EAX20_ListenerProperties
           = { 0x306a6a8, 0xb224, 0x11d2, { 0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } };
      
       const GUID DSPROPSETID_EAX20_BufferProperties
           = { 0x306a6a7, 0xb224, 0x11d2, {0x99, 0xe5, 0x0, 0x0, 0xe8, 0xd8, 0xc7, 0x22 } };
      
       EAXSet eaxSet; // EAXSet function, retrieved if EAX Extension is supported
       EAXGet eaxGet; // EAXGet function, retrieved if EAX Extension is supported
#endif // _USEEAX
      
       bool isInitialised;
       ALCdevice* mSoundDevice;
       ALCcontext* mSoundContext;
      
       std::string mAudioPath;
      
       bool isSoundOn;

       ALfloat position[3];
       ALfloat velocity[3];
       ALfloat orientation[6];
      
       // Needed because of hardware limitation
       // Audio sources
       unsigned int mAudioSourcesInUseCount;
       unsigned int mAudioSources[ MAX_AUDIO_SOURCES ];
       bool         mAudioSourceInUse[ MAX_AUDIO_SOURCES ];
      
       // Audio buffers
       unsigned int mAudioBuffersInUseCount;
       unsigned int mAudioBuffers[ MAX_AUDIO_BUFFERS ];
       bool         mAudioBufferInUse[ MAX_AUDIO_BUFFERS ];
       char         mAudioBufferFileName[ MAX_AUDIO_BUFFERS ][ MAX_FILENAME_LENGTH ];
  
       // Function to check if the soundFile is already loaded into a buffer
       int locateAudioBuffer( std::string filename );
       int loadAudioInToSystem( std::string filename );
       bool loadWAV( std::string filename, ALuint pDestAudioBuffer );
       bool loadOGG( std::string filename, ALuint pDestAudioBuffer );
       // TODO bool loadAU( std::string filename, ALuint pDestAudioBuffer );
      
       // Ogg Vorbis extension
       bool bOggExtensionPresent;
      
   public:
       static SoundManager* mSoundManager;
      
       SoundManager( void );
       virtual ~SoundManager( void );
       void SoundManager::selfDestruct( void );
       static SoundManager* createManager( void );
       static SoundManager* getSingletonPtr( void ) { return mSoundManager; };

       bool init( void );
       bool getIsSoundOn( void ) { return isSoundOn; };
       void setAudioPath( char* path ) { mAudioPath = std::string( path ); };
      
       bool checkALError( void );
       bool checkALError( std::string pMsg );
      
       /** See http://www.openal.org/windows_enumeration.html for installing other
       *   devices. You should at least have "Generic Hardware".
       */
       std::string listAvailableDevices( void );
      
       // careful : testSound should not be used it doesn't use the resource limitation
       void testSound( const char* wavFile );
      
       // Aquire an Audio Source
       // filename = pass in the sound file to play for this source (ex. "myfile.wav")
       // audioId   = returns the AudioSource identifier you will need for the PlayAudioSource();
       bool loadAudio( std::string filename, unsigned int *audioId, bool loop );
       bool releaseAudio( unsigned int audioID );
      
       // deprecated
       bool aquireAudioSource( char* file, unsigned int *audioId )
           { return loadAudio( std::string(file), audioId, false ); };
      
       // Returns true if the audio is started from the beginning
       // false if error or if already playing
       bool playAudio( unsigned int audioId, bool forceRestart );
       bool stopAudio( unsigned int audioID );
       bool stopAllAudio( void );

       bool pauseAudio( unsigned int audioID );
       bool pauseAllAudio( void );
       bool resumeAudio( unsigned int audioID );
       bool resumeAllAudio( void );
      
       bool setSoundPosition( unsigned int audioID, Vector3 position );
      
       bool setSoundPosition( unsigned int audioID, Vector3 position,
           Vector3 velocity, Vector3 direction );
          
       bool setSound( unsigned int audioID, Vector3 position,
           Vector3 velocity, Vector3 direction, float maxDistance,
           bool playNow, bool forceRestart, float minGain );
      
       bool setListenerPosition( Vector3 position, Vector3 velocity,
		   Vector3 direction, Vector3 up );
      
       bool isOggExtensionPresent( void );
      
      
       /**
        * Preload audio files into the system.
        * Not obligatory, the files can also be loaded on the fly.
        */
       bool loadDefaultSounds( std::string filename );
       // Function to trim the trailing crap from a string.
       void trimTrailingSpace( char *s );

};

#endif /*__SOUNDMANAGER_H__*/